﻿using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using BBCode.Tags;
using BBCode.Template;

namespace BBCode.Nodes
{
    /// <summary>
    /// BBCode object for the more Complex BBCodes
    /// </summary>
    public class BBCodeComplex : BBCode, INestableNode
    {
        private readonly Dictionary<string, string> _options;
        private readonly string _optionsString;

        #region constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="BBCodeComplex"/> class.
        /// </summary>
        /// <param name="tag">The tag.</param>
        /// <param name="text">The text.</param>
        /// <param name="nodeIndex">Index of the node.</param>
        /// <param name="options">The options.</param>
        /// <param name="opening">The opening.</param>
        /// <param name="closing">The closing.</param>
        public BBCodeComplex(ITag tag, string text, NodeIndex nodeIndex, string options, string opening, string closing)
            : base(tag, text, nodeIndex, opening, closing)
        {
            _optionsString = options;
            _options = new Dictionary<string, string>();

            MatchCollection matchCollection = Regex.OptionRegex.Matches(_optionsString);

            bool first = true;
            foreach (Match m in matchCollection)
            {
                if (first)
                {
                    if (string.IsNullOrEmpty(m.Groups["Property"].Value))
                    {
                        _options.Add("DEFAULT", m.Groups["Value"].Value);
                        continue;
                    }
                    first = false;
                }

                if (!string.IsNullOrEmpty(m.Groups["Property"].Value))
                {
                    if (!_options.ContainsKey(m.Groups["Property"].Value))
                    {
                        _options.Add(m.Groups["Property"].Value.ToUpper(), m.Groups["Value"].Value);
                    }
                }
            }
        }

        #endregion

        #region INestableNode Members

        /// <summary>
        /// Prints the specific Node.
        /// </summary>
        /// <param name="shouldAutoParseLinks">if set to <c>true</c> [should auto parse links].</param>
        /// <returns></returns>
        public new string Print(bool shouldAutoParseLinks)
        {
            var textBuilder = new StringBuilder(Text);

            //Remove the opening and closing
            textBuilder.Remove(0, Opening.Length);
            textBuilder.Remove(textBuilder.Length - Closing.Length, Closing.Length);

            //Get the template, fill it and process it!.
            switch (Tag.ParseType)
            {
                case ParseType.Clean:
                    //Clean the node, leaving the innertext
                    return textBuilder.ToString();
                case ParseType.Remove:
                    //Remove it ALL!
                    return string.Empty;
                default:
                    //Default is always to print it as it should be printed!
                    var template = Tag.GetTemplate();
                    if (HasChildren)
                    {
                        //Go through the nodes, in the right order
                        var orderedNodes = from n in Children
                                                                 orderby n.Tag.Priority descending
                                                                 select n;

                        //Set the ID's of all the nodes
                        foreach (var node in orderedNodes)
                        {
                            var firstIndex = textBuilder.ToString().IndexOf(node.Text);
                            textBuilder.Replace(node.Text, node.ID, firstIndex, node.Text.Length);
                        }

                        //Check if we allow children
                        if (Tag.CanHaveChildren)
                        {
                            //Auto parsing goes here!
                            if (shouldAutoParseLinks)
                            {
                                var matches = Regex.AutoParseRegex.Matches(textBuilder.ToString());

                                foreach (Match m in matches)
                                {
                                    textBuilder.Replace(m.Value,
                                                        "<a href=\"" + m.Value + "\" rel=\"nofollow\">" + m.Value +
                                                        "</a>");
                                }
                            }
                        }

                        //Replace the ID's with the right text
                        foreach (var node in Children)
                        {
                            textBuilder.Replace(node.ID, node.Print(shouldAutoParseLinks));
                        }

                        template["INNERTEXT"] = textBuilder;
                    }
                    else
                    {
                        template["INNERTEXT"] = textBuilder;
                    }

                    foreach (var keyValuePair in _options)
                    {
                        template[keyValuePair.Key] = keyValuePair.Value;
                    }

                    return template.Process();
            }
        }

        #endregion
    }
}